<template>
  <div class="assign-tree-dimension-new">
    <section class="header-bar">
      <div class="current-user">
        <div v-if="assignmentId">
          <span class="label">已选择用户：</span>
          <span class="user-name-id">{{ userInfo.userName || '' }}({{ userInfo.userId || '' }})</span>
        </div>
        <div v-else>
          <span>未选择用户</span>
        </div>
      </div>
      <Button type="primary" :disabled="!assignmentId" @click="save()">{{ $t('common.save') }}</Button>
    </section>
    <el-tree
      v-if="dimensionDataUrl"
      class="treeStyle"
      ref="objectTreeNew"
      node-key="orgId"
      highlightCurrent
      lazy
      :default-checked-keys="checkedList"
      :load="loadNode"
      :props="treeProps"
      :show-checkbox="true"
      :empty-text="hintText"
    ></el-tree>
  </div>
</template>

<script>
import locales from './locales.js'
import dataPermissionAPI from '@/api/dataPermissionAPI.js'
import { CONTROL_LEVEL_ORG, CONTROL_LEVEL_ROLE, CONTROL_LEVEL_USER } from './const.js'

const getQueryString = (url = '') => {
  const query = {}
  if (!url) return query
  const queryStr = url?.split('?')[1] || ''
  const arr = queryStr?.split('&') || []
  for (const item of arr) {
    const [k, v] = item?.split('=')?.map(decodeURIComponent)
    query[k] = v || ''
  }
  return query
}

export default {
  name: 'AssignTreeDimension',
  mixins: [locales],
  props: {
    tenantCode: {
      type: String,
      required: true
    },
    dimensionId: {
      type: String,
      default: ''
    },
    assignmentId: {
      type: String,
      default: ''
    },
    dimensionCode: {
      type: String,
      default: ''
    },
    controlLevel: {
      type: Number,
      default() {
        return 0
      }
    },
    activeTab: {
      type: String,
      default: ''
    },
    userInfo: {
      type: Object,
      default: () => ({}),
      required: true
    }
  },
  data() {
    return {
      treeProps: {
        children: 'children',
        label: 'orgName'
      },
      searchForm: {
        tenantCode: this.tenantCode,
        assignmentId: this.assignmentId,
        dimensionCode: this.dimensionCode,
        dimensionDataCode: '',
        dimensionDataName: ''
      },
      checkedList: [],
      checkedNodes: [],
      hintText: '',
      dimensionDataUrl: '',
      treeRef: null,
      treeNodeDatas: []
    }
  },
  created() {
    this.getDimensionDataUrl()
    this.initHint()

    const watchTreeDataChange = async () => {
      const submitData = await this.selectedChangeDialog()
      submitData && this.save()
    }

    // 关闭当前sidelip页面，如果数据变动，提示用户是否需要保存
    // 注册关闭弹窗前回调
    this.$emit('closeSildePageHook', watchTreeDataChange)

    // 路由切换，如果数据变动，提示用户是否需要保存
    // 注册切换路由的监听任务
    window?.$app?.routeChangeTasks?.push(watchTreeDataChange)
  },
  methods: {
    init() {
      this.checkedList.splice(0)
      this.checkedNodes.splice(0)
      if (!this.searchForm.assignmentId) {
        this.initHint()
        return
      }
      this.hintText = this.$t('module.dataPermission.warning.hintWait')
      // 初始化树数据
      dataPermissionAPI.queryOrgTreeDimensionData(this.searchForm).then(res => {
        const data = res?.data || []
        this.hintText = this.$t('module.dataPermission.noData')
        // 设置选中节点&半选节点
        this.checkedList = data.map(d => d.dimensionDataId)
        this.checkedNodes = data
        if (!this.treeRef) {
          this.treeRef = this.$refs['objectTreeNew']
        }
        const treeRef = this.treeRef || this.$refs['objectTreeNew']
        const rootNode = treeRef?.root?.childNodes[0] || {}
        treeRef.setCheckedKeys(this.checkedList)
        this.setHalfCheckedNode(rootNode)
      })
    },
    initHint() {
      if (this.controlLevel == CONTROL_LEVEL_ORG) {
        this.hintText = this.$t('module.dataPermission.warning.hintSelectOrg')
      } else if (this.controlLevel == CONTROL_LEVEL_ROLE) {
        this.hintText = this.$t('module.dataPermission.warning.hintSelectRole')
      } else if (this.controlLevel == CONTROL_LEVEL_USER) {
        this.hintText = this.$t('module.dataPermission.warning.hintSelectUser')
      }
    },
    getDimensionDataUrl() {
      const { dimensionId, tenantCode } = this
      const bodyParam = {
        pageNum: 1,
        pageSize: 10,
        dimensionId,
        tenantCode,
        condition: {
          dimensionId,
          tenantCode
        }
      }
      dataPermissionAPI?.getDimensionDataUrl(bodyParam).then(res => {
        const records = res?.records || []
        const target = records.find(r => r.dimensionId === dimensionId) || {}
        this.dimensionDataUrl = target?.dimensionDataUrl
      })
    },
    loadNode(node, resolve) {
      if (node.level === 0) {
        const reqParam = getQueryString(this.dimensionDataUrl)
        dataPermissionAPI?.getOrgDataByPath(reqParam).then(res => {
          const rootNode = res?.data
          rootNode.isRoot = true
          resolve(rootNode ? [rootNode] : [])
          this.treeNodeDatas.push(rootNode)
        })
        return
      }

      const param = {
        orgTypeFilter: 1,
        orgPath: node?.data?.orgPath || ''
      }

      dataPermissionAPI?.getAuthorizedOrgsNew(param).then(res => {
        const data = res?.data || []
        node.data.children = data
        node.data.hasChildren = Boolean(data.length)
        resolve(data)
        this.setHalfCheckedNode(node)
        data.forEach(item => this.treeNodeDatas.push(item))
      })
    },
    getSubmitDataList() {
      if (!this?.treeRef) {
        this.treeRef = this.$refs['objectTreeNew']
      }
      const localCheckedNodes = this?.treeRef?.getCheckedNodes()
      const halfCheckedNodes = this?.treeRef?.getHalfCheckedNodes()

      if (!localCheckedNodes.length && !halfCheckedNodes.length) {
        // 未选择任何权限
        return []
      }

      const targetNodes = []
      const excluded = '__excluded__'
      const dimensionDataList = []
      const { checkedNodes: remoteCheckedNodes } = this
      const halfCheckedNodePaths = halfCheckedNodes.map(i => i.orgPath)
      const excludeIds = halfCheckedNodes.map(i => i.orgId) || [] // 半选节点默认排除（不提交）
      const localCheckedIds = localCheckedNodes.map(i => i.orgId)
      let hasRootNode = false
      // 已知树节点中未选中的节点ID（非半选且非选中状态）
      const unCheckedNodes = this.treeNodeDatas.filter(
        node => !excludeIds.includes(node.orgId) && !localCheckedIds.includes(node.orgId)
      )
      const unCheckedNodeIds = unCheckedNodes.map(i => i.orgId)
      const unCheckedNodePaths = unCheckedNodes.map(i => i.orgPath)

      // 处理本地已知树节点中已被勾选的节点
      for (const node of localCheckedNodes) {
        // 如果根节点被选中，那么只提交根节点即可，跳出循环
        const targetIds = targetNodes.map(t => t?.orgId)
        if (node?.isRoot) {
          targetNodes.push(node)
          hasRootNode = true
          break
        } else {
          // 如果当前节点没有子节点入栈
          if (!node?.hasChildren && !node[excluded]) {
            targetNodes.push(node)
          } else {
            // 当前节点有子节点，需要判断其子节点是否全部被选中，若是，则只需要提交其根节点即可（当前节点入栈，其子节点不入栈）
            if (node[excluded]) {
              excludeIds.push(node.orgId)
              continue
            }
            const total = node.children.length
            const selectedChildNodes = localCheckedNodes.filter(n => {
              if (n?.parentId === node.orgId) {
                n[excluded] = true // 给当前节点的子节点做标记
                return true
              }
              return false
            })
            if (total === selectedChildNodes.length || (!targetIds.includes(node.orgId) && !node[excluded])) {
              targetNodes.push(node)
            }
          }
        }
      }
      targetNodes.forEach(item => {
        if (!item.disabled) {
          dimensionDataList.push({
            dimensionDataCode: item.orgCode,
            dimensionDataId: item.orgId,
            dimensionDataName: item.orgName,
            dimensionDataPath: item.orgPath
          })
        }
      })

      // 若本地勾选了根节点 不再判断已分配权限是否保留
      if (hasRootNode) {
        return dimensionDataList
      }

      // 判断已分配的权限是否需要保留
      for (const remoteNode of remoteCheckedNodes) {
        const { dimensionDataId, dimensionDataPath, dimensionDataCode } = remoteNode
        const parentPath = dimensionDataPath.replace(`/${dimensionDataCode}`, '')

        // 半选节点、未选中节点中包含已分配权限的组织ID 或 未选中节点的路径中包含了已分配权限的父路径，说明不再保留当前的权限
        if (
          excludeIds.includes(dimensionDataId) ||
          unCheckedNodeIds.includes(dimensionDataId) ||
          unCheckedNodePaths.includes(parentPath)
        ) {
          continue
        }

        for (const halfCheckedNodePath of halfCheckedNodePaths) {
          const dimensionDataIdList = dimensionDataList.map(i => i.dimensionDataId)
          const dimensionDataPaths = dimensionDataList.map(i => i.dimensionDataPath)
          if (
            !dimensionDataPaths.includes(parentPath) &&
            !dimensionDataIdList.includes(dimensionDataId) &&
            dimensionDataPath !== halfCheckedNodePath &&
            dimensionDataPath.startsWith(halfCheckedNodePath)
          ) {
            dimensionDataList.push({
              dimensionDataCode: remoteNode.dimensionDataCode,
              dimensionDataId: remoteNode.dimensionDataId,
              dimensionDataName: remoteNode.dimensionDataName,
              dimensionDataPath: remoteNode.dimensionDataPath
            })
          }
        }
      }

      return dimensionDataList
    },
    save(assignmentId = '') {
      if (!assignmentId && !this.assignmentId) return

      const dimensionDataList = this.getSubmitDataList()
      const param = {
        assignmentId: assignmentId || this.assignmentId,
        dimensionDataList
      }
      console.log('dimensionDataList: ', dimensionDataList)

      dataPermissionAPI
        .saveAssignedTreeDimensionData(param)
        .then(() => {
          this.$message.success({
            content: this.$t('module.dimension.warning.updateSuccessfully'),
            duration: 3
          })
          this.init()
        })
        .catch(err => {
          this.$message.error(err.msg)
        })
    },
    submitDataChange() {
      const currentCheckedList = this.getSubmitDataList().map(d => d.dimensionDataId)
      const { checkedList: previous } = this
      if (currentCheckedList.length !== previous.length) return true
      const ret = currentCheckedList.filter(id => !previous.includes(id)) || []
      return Boolean(ret.length)
    },
    selectedChangeDialog() {
      return new Promise(resolve => {
        const dataChange = this.submitDataChange()
        if (dataChange) {
          this.$confirm
            .warning('数据已变化,是否提交数据？')
            .then(() => {
              resolve(true)
            })
            .catch(_ => resolve(false))
        } else {
          resolve(false)
        }
      })
    },
    setHalfCheckedNode(node) {
      if (!this.checkedNodes.length) return
      const {
        level,
        data,
        data: { orgPath, orgCode },
        childNodes,
        checked
      } = node
      const orgPaths = this.checkedNodes.map(i => i.dimensionDataPath)
      if (level === 0 || !data) return
      if (!orgPaths.includes(orgPath)) {
        if (!checked && orgPaths.some(p => p.startsWith(orgPath) && p.split('/').indexOf(orgCode) > -1)) {
          // setChecked(value, deep, recursion, passValue) setChecked方法是element tree的内部方法 未对外开放
          node?.setChecked('half', false, false, false) // 设置半选
          if (childNodes && childNodes.length) {
            childNodes.forEach(childNode => this.setHalfCheckedNode(childNode))
          }
        }
      }
    }
  },
  watch: {
    // 切换用户，如果数据变动，提示用户是否需要保存
    async assignmentId(newVal, oldVal) {
      this.searchForm.assignmentId = newVal
      // this.init()
      if (newVal !== oldVal && !oldVal) {
        this.init()
        return
      }
      const submitData = await this.selectedChangeDialog()
      if (submitData) {
        this.save(oldVal)
      } else {
        this.init()
      }
    },
    // 切换tab页面，如果数据变动，提示用户是否需要保存
    async activeTab() {
      if (!this?.treeRef) {
        return
      }
      const submitData = await this.selectedChangeDialog()
      submitData && this.save()
    }
  }
}
</script>

<style lang="less">
.assign-tree-dimension-new {
  height: 100%;

  .header-bar {
    padding: 0 10px 10px 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    .current-user {
      margin-right: 16px;
      span {
        display: inline-block;
      }
      .label {
        color: #796e6e;
      }
      .user-name-id {
        color: #ff6f4b;
      }
    }
  }

  .tree-menu {
    width: 140px;
    height: 50px;
    position: absolute;
    display: none;
    border-radius: 4px;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
    background-color: white;
    z-index: 99;

    .menu-item {
      width: 100%;
      height: 25px;
      margin: 0px auto;
      padding: 3px 0 0 10px;
      cursor: pointer;
    }

    .menu-item:hover {
      color: #ff6f4b;
      background: #fdf0ef;
    }
  }

  .el-checkbox__input.is-disabled.is-checked .el-checkbox__inner {
    background-color: #f2f6fc !important;
    border-color: #dcdfe6 !important;
  }

  .el-checkbox__input.is-disabled.is-checked .el-checkbox__inner:after {
    background-color: #f2f6fc;
  }
}
</style>
